﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using TiledLib;

namespace RunnerX
{
    class RunnerLevel
    {
        public Map LevelMap { get; set; }

        private readonly Player _player;

        private Vector2 _camera = Vector2.Zero;

        private GraphicsDevice _gd;
        
        private List<Rectangle> _collisionRects = new List<Rectangle>(); 
        public RunnerLevel(Map map, Player player, GraphicsDevice gd)
        {
            LevelMap = map;
            _player = player;
            _gd = gd;
            var collisionTileLayer = LevelMap.GetLayer("CollisionLayer") as TileLayer;
            for (int i = 0; i < collisionTileLayer.Width; i++)
            {
                for (int j = 0; j < collisionTileLayer.Height; j++)
                {
                    var tile = collisionTileLayer.Tiles[i, j];
                    if (tile == null) continue;

                    _collisionRects.Add(new Rectangle(i*32, j*32,
                        32, 32));
                }
            }
        }

        public void Update(GameTime gametime)
        {
            // Get the keyboard state
            var keyState = Keyboard.GetState();

            CheckForCollisions();

            if (_player.State == PlayerState.Falling)
                _player.Y += 4;

            if(_player.State == PlayerState.Running)
            {
                if(keyState.IsKeyDown(Keys.Right))
                {
                    _player.X += 4;
                }
                if(keyState.IsKeyDown(Keys.Left))
                {
                    _player.X -= 4;
                }
            }
            UpdateCamera(keyState);

            _player.Update(gametime);
        }

        private void CheckForCollisions()
        {
            foreach (var collisionRect in _collisionRects)
            {
                if (collisionRect.Intersects(_player.BoundingBox))
                {
                    _player.State = PlayerState.Running;
                }
            }
        }


        private void UpdateCamera(KeyboardState keyboardState)
        {
            // Direction of camera movement.
            var cameraMovement = Vector2.Zero;

            // otherwise we use the arrow keys
            if (keyboardState.IsKeyDown(Keys.Left))
                cameraMovement.X = -1;
            else if (keyboardState.IsKeyDown(Keys.Right))
                cameraMovement.X = 1;
            if (keyboardState.IsKeyDown(Keys.Up))
                cameraMovement.Y = -1;
            else if (keyboardState.IsKeyDown(Keys.Down))
                cameraMovement.Y = 1;

            // Camera velocity scaling.
            cameraMovement *= 4f;

            MoveCamera(cameraMovement);
        }

        private void MoveCamera(Vector2 cameraMovement)
        {
            _camera += cameraMovement;

            // Clamp the camera so it never leaves the visible area of the map.
            var cameraMax = new Vector2(
                LevelMap.Width * LevelMap.TileWidth - _gd.Viewport.Width,
                LevelMap.Height * LevelMap.TileHeight - _gd.Viewport.Height);

            _camera = Vector2.Clamp(_camera, Vector2.Zero, cameraMax);
        }

        public void Draw(SpriteBatch sb)
        {
            // Creates a matrix for the camera to offset everything we draw, the map and our objects.
            //      Since the camera coords are where the camera is, we offset everything by the negative
            //      of that to simulate a camera moving. Also cast to ints to avoid filtering artifacts.
            var cameraMatrix = Matrix.CreateTranslation(-(int) _camera.X, -(int) _camera.Y, 0);
            sb.Begin(0, null, null, null, null, null, cameraMatrix);

            // Use map draw overload so we only draw what's in the visible area of the map.
            var visibleArea = new Rectangle(
                (int) _camera.X,
                (int) _camera.Y,
                _gd.Viewport.Width,
                _gd.Viewport.Height);

            LevelMap.Draw(sb, visibleArea);
            _player.Draw(sb);
            

            sb.End();
        }
    }
}
